<?php

class CSVerterSABC
{

/*

	Class: CSVerterSABC v0.2.5
	http://code.google.com/p/ofcom-csverter/


	Copyright (c) 2011 Ian Galpin.

	Permission is hereby granted, free of charge, to any person obtaining a copy
	of this software and associated documentation files (the "Software"), to deal
	in the Software without restriction, including without limitation the rights
	to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
	copies of the Software, and to permit persons to whom the Software is
	furnished to do so, subject to the following conditions:

	The above copyright notice and this permission notice shall be included in
	all copies or substantial portions of the Software.

	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
	THE SOFTWARE.

*/



	/**
	 * Configuration
	 * - optionally set these values with $object->var_name = 'value';
	 */

	# Area codes with mixed format and using SABCD (specify SABCD)
	var $mixed5 = '/(1(3873|5(242|39[456])|697[347]|768[347]|9467))/';

	# Area codes with mixed format and using SABC (specify SABC only; D is the first digit of local number)
	var $mixed4 = '/(1(387|5(24|39)|697|768|946))/';

	# Area codes using ELNS and 4 digits (specify SABC)
	var $elns4 = '/(1(229|3(39|88)|4(23|3[047])|507|686|8(47|51|90)|9(64|75)))/';

	# Area codes using ELNS and 3 digits (specify SABC as SAB\d)
	var $elns3 = '/(191\d)/';

	# Area codes using ELNS and 2 digits (specify SABC as SA\d\d)
	var $elns2 = '/(2[38]\d\d)/';

	# Director area codes 3 digit 1x1 (specify SABC as SAB\d)
	var $director3 = '/(1[23456]1\d)/';

	# Director area codes 2 digit 2x (specify SABC as SA\d\d)
	var $director2 = '/(20\d\d)/';

	# Area codes with 3 digits using only SAB (specify SABC as SAB\d)
	var $sab37 = '/(1(0\d\d|\d1\d|1\d\d))/';

	# Area codes with 2 digits using only SA (specify SABC as SA\d\d)
	var $sa28 = '/(2[03489]\d\d)/';

	# Area codes beginning 76 protected for use as 'Mobile Number Portability Codes'
	var $protected = '/(^7(6(0[3-9]|1[0-9]|2[0-2]|3[0-9]|5[0-35-8]|8[02-9]|9[0-2]|9[4-8])|99[1-8]))/';

	# Area code wording for unassigned entries
	var $unassigned = 'Geographic - unassigned';

	# Area code pattern for codes with former assignments
	var $unassignedlong = '/(Geographic \- unassigned)(.*)/';

	# Pattern for 'ELNS' area wording
	var $elnstext = '/ELNS/';

	# Pattern for 'Mixed' area wording
	var $mixedtext = '/Mixed/';

	# Pattern for 'Director' area wording
	var $directortext = '/Director/';

	# Pattern for 'X Digit Code Area' wording
	var $dcodearea = '/([2345]) [Dd]igit [Cc]ode [Aa]rea/';

	# Pattern for 'X Digit Area Code' wording
	var $dareacode = '/([2345]) [Dd]igit [Aa]rea [Cc]ode/';

	# Pattern for 'area code'/'code area' wording
	var $areacodearea = '/([2345]) [Dd]igit ([Aa]rea [Cc]ode|[Cc]ode [Aa]rea)/';

	# Pattern for 'protected' usage not needing Length/Director/ELNS data
	var $expansion = '/([Ee](xpansion|mergency))/';

	# Pattern for mismatched parentheses on 'former assignment' notes
	var $mismatched = '/^(\ )?\([^\(\)]+\([^\(\)]+\)$/';

	# Correct spelling/naming for areas (needs SABC specified, SABCD for all Mixed and for 4 digit code ELNS areas)
	var $spelling = array(
		12290 => 'Barrow-in-Furness/Millom National Dialling',
		12291 => 'Barrow-in-Furness/Millom National Dialling',
		1233 => 'Ashford (Kent)',
		1271 => 'Barnstaple',
		1284 => 'Bury St Edmunds',
		1286 => 'Caernarfon',
		1289 => 'Berwick-upon-Tweed',
		1384 => 'Dudley',
		13884 => 'Bishop Auckland',
		13885 => 'Stanhope',
		1477 => 'Holmes Chapel',
		1482 => 'Kingston-upon-Hull',
		1491 => 'Henley-on-Thames',
		15072 => 'Horncastle',
		15075 => 'Horncastle',
		15395 => 'Grange-over-Sands',
		1559 => 'Llandysul',
		1636 => 'Newark-on-Trent',
		1841 => 'Padstow',
		18517 => 'Stornoway',
		18518 => 'Stornoway',
		1877 => 'Callander',
		1878 => 'Lochboisdale',
		1889 => 'Rugeley',
		18906 => 'Ayton',
		1915 => 'Sunderland',
		1934 => 'Weston-super-Mare',
		19467 => 'Gosforth',
		1959 => 'Westerham',
		2099 => 'Unusable (Emergency Services)',
		2199 => 'Unusable (Emergency Services)',
		2299 => 'Unusable (Emergency Services)',
		2399 => 'Unusable (Emergency Services)',
		2499 => 'Unusable (Emergency Services)',
		2599 => 'Unusable (Emergency Services)',
		2699 => 'Unusable (Emergency Services)',
		2799 => 'Unusable (Emergency Services)',
		2810 => 'Northern Ireland National Dialling',
		2811 => 'Northern Ireland National Dialling',
		2843 => 'Newcastle (Co. Down)',
		2890 => 'Belfast',
		2891 => 'Bangor (Co. Down)',
		2899 => 'Unusable (Emergency Services)',
		2999 => 'Unusable (Emergency Services)'
	);

	# Add Notes for disputed area codes (needs SABCD for all 5 and 4 digit code Mixed areas and for 4 digit code ELNS areas, and only SABC for all others)
	var $addnotes = array(
		12290 => 'Millom added to \'Barrow-in-Furness National Dialling\'',
		12291 => 'Millom added to \'Barrow-in-Furness National Dialling\'',
		1233 => ' In 2003, Oftel suggested continuing with \'Ashford\'. C&W suggested \'Ashford (Kent)\'. Renamed in 2003, but not shown in Ofcom\'s list of areas renamed in 2003. Correctly listed in NTNP since 2003. Missing \'(Kent)\' clarification in SABC 1998- and ongoing.',
		1248 => ' In 2003, Oftel suggested Bangor which clashes with 28 91. BT and C&W suggested \'Bangor (Wales)\'.',
		1268 => ' In 2003, Oftel suggested \'Canvey Island\'. BT and C&W suggested \'Basildon\'.',
		1271 => ' Incorrect spelling \'Barnstable\' 1998-2010 (and still incorrect in NTNP).',
		1284 => ' Incorrect punctuation \'Bury-St-Edmunds\' 1998-2010 (and still incorrect in NTNP).',
		1286 => ' Incorrect spelling \'Caernarvon\' 1998-2010 (and still incorrect in NTNP).',
		1289 => ' Incorrect spelling \'Berwick-on-Tweed\' 1998-2010 (and still incorrect in NTNP).',
		1294 => ' In 2003, Oftel suggested continuing with \'Ardrossan\'. C&W suggested \'Irvine\'.',
		1333 => ' In 2003, Oftel suggested continuing with \'Peat Inn\' even though \'Peat Inn\' is in the 1334 area. 1333 should be called \'Leven (Fife)\'.',
		1334 => ' In 2003, Oftel suggested \'St Andrews\'. In renaming 1334 in 2003, Oftel renamed the wrong area.',
		1340 => ' No exchange in \'Craigellachie\'. \'Aberlour\' would be a better name.',
		1355 => ' In 2003, Oftel suggested \'Kilbride\'. BT and C&W suggested continuing with \'East Kilbride\'.',
		1357 => ' In 2003, Oftel suggested \'East Kilbride\'. BT suggested continuing with \'East Kilbride\' which clashes with 1355. C&W suggested \'Strathaven\'. Renamed in 2003, but not shown in Ofcom\'s list of areas renamed in 2003.',
		1375 => ' In 2003, Oftel suggested continuing with \'Stanford-le-Hope\'. BT and C&W suggested \'Grays Thurrock\'. BT incorrectly referred to the existing name as \'Stanford Le Hope\' in 2003.',
		1384 => ' Incorrect naming \'Stourbridge\' (in SABC) 2003-2007. Correctly listed as \'Dudley\' in NTNP.',
		13882 => ' No exchange in \'Stanhope\'. It is in \'Eastgate\'.',
		13884 => ' In their 2003 consultation document, Oftel listed \'Stanhope\' as (4). BT pointed out that (5) was the correct value.',
		13885 => ' No exchange in \'Stanhope\'. It is in \'Eastgate\'.',
		14372 => ' \'Clunderwen\' is the correct Welsh spelling.',
		14373 => ' \'Clunderwen\' is the correct Welsh spelling.',
		14374 => ' \'Clunderwen\' is the correct Welsh spelling.',
		14375 => ' \'Clunderwen\' is the correct Welsh spelling.',
		1438 => ' In 2003, Oftel suggested continuing with \'Knebworth\'. BT and C&W suggested \'Stevenage\'.',
		1477 => ' Incorrect spelling \'Holmes Chappel\' (in SABC) 2003-2007.',
		1482 => ' \'Hull\' should be \'Kingston-upon-Hull\'.',
		1491 => ' Incorrect punctuation \'Henley on Thames\' 1998-2010 (and still incorrect in NTNP).',
		15072 => ' \'Spilsby\' removed from NTNP 2003-2005 then incorrectly re-added in 2005. \'Spilsby\' is 1790. 1507 2 should be called \'Horncastle\'.',
		15074 => ' In 2003, Oftel suggested \'Alford\' which clashes with 1975. C&W suggested \'Alford (Lincs)\'. Listed as \'Alford (Lincolnshire)\' in SABC briefly in 2003 then corrected.',
		15075 => ' In 2003, Oftel suggested continuing with \'Spilsby\'. BT pointed out that \'Spilsby\' is 1790. \'Spilsby\' removed from NTNP 2003-2005 then incorrectly re-added in 2005. 1507 5 should be called \'Horncastle\'.',
		15395 => ' Incorrect punctuation \'Grange over Sands\' 1998-2010 (and incorrect capitalisation \'Grange-Over-Sands\' in NTNP is still ongoing).',
		1559 => ' Incorrect spelling \'Llandyssul\' 1998-2010 (and still incorrect in NTNP).',
		1562 => ' In 2003, Oftel suggested continuing with \'Stourbridge\'. C&W suggested \'Kidderminster\'.',
		1594 => ' In 2003, Oftel suggested continuing with \'Lydney\'. C&W suggested \'Dean\'.',
		1598 => ' In 2003, Oftel suggested \'Lynton\'. C&W suggested \'Barnstable\' (incorrect spelling) which clashes with 1271.',
		1603 => ' Unwanted trailing space after name for more than a decade in SABC.',
		1636 => ' \'Newark\' should be \'Newark-on-Trent\'.',
		1668 => ' In 2003, Oftel suggested \'Bamburgh\'. C&W suggested \'Wooler\'.',
		1684 => ' In 2003, Oftel suggested continuing with \'Hanley Swan\'. BT suggested \'Tewkesbury\'. C&W suggested \'Malvern\'.',
		16864 => ' Incorrect spelling \'Llandiloes\' in 2003 Oftel consultation document.',
		16977 => ' Correctly listed as 16977 in NTNP 2003-2004 and in SABC 2001-2002. Incorrect since that time, and still incorrect. ** 16977 is a FIVE-DIGIT AREA CODE **',
		1707 => ' In 2003, Oftel suggested \'Welwyn Garden City\'. BT and C&W suggested \'Potters Bar\'.',
		1807 => ' \'Ballindalloch\'.',
		1821 => ' In 2003, Oftel suggested \'Kinross\'. BT pointed out \'Kinross\' was 1577 and many miles away. BT suggested \'Kinrossie\' or \'Errol\'.',
		1832 => ' In 2003, Oftel suggested continuing with \'Clopton\'. C&W suggested \'Oundle\'.',
		1841 => ' In 2003, Oftel suggested continuing with \'Newquay\' which clashes with 1637. C&W suggested \'Padstow\'. The C&W suggestion was ignored by Oftel. 1841 should be \'Padstow\'.',
		1843 => ' Thanet is a region, not a town.',
		18517 => ' Spelling error \'Stornaway\' in 2003 Oftel consultation document.',
		18518 => ' Spelling error \'Stornaway\' in 2003 Oftel consultation document.',
		1864 => ' No exchange in \'Abington\'. It is in \'Crawford\'.',
		1877 => ' Incorrect spelling \'Callandar\' (in NTNP) 2003- and ongoing.',
		1878 => ' Incorrect spelling \'Lohboisdale\' (in SABC) 1998-2004.',
		1885 => ' In 2003, Oftel suggested \'Pencombe\'. C&W suggested continuing with \'Bromsgrove\'. The C&W suggestion was ignored by Oftel. In renaming 1885 in 2003, Oftel renamed the wrong area.',
		1886 => ' In 2003, Oftel suggested continuing with \'Bromyard\'. C&W suggested \'Leigh Sinton\'. Bromyard businesses use 1885. \'Knightwick\' would be a better name for 1886.',
		1889 => ' Incorrect spelling \'Rugely\' (in NTNP) 2003- and ongoing.',
		18096 => ' Listed as \'Coldstream\' in SABC in error 2003-2005, then corrected to \'Ayton\' 2005 onwards.',
		1912 => ' \'Newcastle-upon-Tyne\' might be a better name.',
		1914 => ' \'Newcastle-upon-Tyne\' might be a better name.',
		1915 => ' Renamed \'Sunderland\' from 2003 onwards in NTNP, but SABC continued to list 1915 as \'Wearside\' until 2007.',
		1916 => ' \'Newcastle-upon-Tyne\' might be a better name.',
		1918 => ' \'Newcastle-upon-Tyne\' might be a better name.',
		1926 => ' In 2003, Oftel suggested \'Warwick\'. C&W suggested continuing with \'Leamington Spa\'.',
		1931 => ' In 2003, Oftel suggested \'Bampton\'. BT and C&W suggested continuing with \'Shap\'.',
		1932 => ' In 2003, Oftel suggested continuing with \'Esher\' which clashes with \'1372\'. C&W suggested \'Weybridge\'.',
		1934 => ' Incorrect capitalisation \'Weston-Super-Mare\' 1998- and ongoing (and still incorrect in NTNP).',
		19467 => ' The \'Mixed\' tag should be moved to the correct column (in SABC), 1998- and ongoing.',
		1959 => ' In 2003, Oftel suggested \'Westerham\'. C&W suggested \'Biggin Hill\' or continuing with \'Swanley\'. Renamed in 2003, but not shown in Ofcom\'s list of areas renamed in 2003. NTNP updated in 2003 but SABC continued to list \'Swanley\' until 2007.',
		19755 => ' In 2003, Oftel suggested \'Alford\' which clashes with 1507. C&W suggested \'Alford (Scotland)\'. NTNP listed \'Alford (Aberdeenshire)\' until 2005 then corrected.',
		1984 => ' No exchange in \'Watchet\'. It is located in \'Williton\'.',
		1987 => ' New area 1987 \'Ebbsfleet\' created in 2008.',
		1992 => ' In 2003, Oftel suggested \'Lea Valley\'. BT suggested continuing with \'Hoddesden\'. C&W suggested \'Waltham Cross\'.',
		1994 => ' In 2003, Oftel suggested \'Whitland\'. BT and C&W suggested continuing with \'St Clears\'.',
		2810 => ' Listed as \'Nothern Ireland National Dialling\' (in SABC) 2003-2010.',
		2811 => ' Listed as \'Nothern Ireland National Dialling\' (in SABC) 2003-2010.',
		2840 => ' Spelling error \'Bambridge\' in 2003 Oftel consultation document.',
		2843 => ' In 2003, Oftel suggested continuing with Newcastle which clashes with 191. C&W suggested \'Newcastle (Co. Down)\'. Missing \'Co. Down\' clarification (in SABC) 1998-2010.',
		2866 => ' Spelling error \'Enniskilen\' in 2003 Oftel consultation document.',
		2881 => ' Spelling error \'Newtonstewart\' in 2003 Oftel consultation document.',
		2890 => ' In 2003, Oftel and C&W suggested \'Belfast\'. Incorrect naming \'Belfast City\' (in SABC) 1998- and ongoing.',
		2891 => ' In 2003, Oftel suggested continuing with Bangor which clashes with 1248. C&W suggested \'Bangor (Co. Down)\'. Missing \'Co. Down\' clarification (in SABC) 1998-2010.'
	);

	# Add Notes for previous area code names, mostly those used before 2003.
	var $oldallocs = array(
		1233 => ' Previously 1233 was \'Ashford\' until 2003.',
		1248 => ' Previously 1248 was \'Bangor (N. Wales)\' until 2003.',
		1268 => ' Previously 1268/1375 both \'Stanford-le-Hope\' until 2003.',
		1275 => ' Previously 1275 was \'Bristol (Outer)\' until 2003.',
		1276 => ' Previously 1276/1344 both \'Ascot\' until 2003.',
		1291 => ' Previously 1291 was \'Shirenewton\' until 2003.',
		1293 => ' Previously 1293/1306 both \'Newdigate\' until 2003.',
		1306 => ' Previously 1293/1306 both \'Newdigate\' until 2003.',
		1322 => ' Previously 1322/1689/1959 all \'Swanley\' until 2003.',
		1327 => ' Previously 1327 was \'Weedon\' until 2003.',
		1334 => ' Previously 1333/1334 both \'Peat Inn\' until 2003.',
		1344 => ' Previously 1276/1344 both \'Ascot\' until 2003.',
		1354 => ' Previously 1354 was \'Doddington\' until 2003.',
		1356 => ' Ofcom say this area was renamed in 2003. However, it is listed as \'Brechin\' both before and after 2003.',
		1357 => ' Previously 1355/1357 were both \'East Kilbride\'.',
		1375 => ' Previously 1268/1375 both \'Stanford-le-Hope\' until 2003.',
		1384 => ' Previously 1384/1562 both \'Stourbridge\' until 2003.',
		1394 => ' Previously 1394 was \'Shottisham\' until 2003.',
		1425 => ' Previously 1425 was \'Burley\' until 2003.',
		1438 => ' Previously 1438/1920 both \'Knebworth\' until 2003.',
		1442 => ' Previously 1442/1582 both \'Markyate\' until 2003.',
		1451 => ' Previously 1451 was \'Bourton-on-the-Water\' until 2003.',
		1454 => ' Previously 1454 was \'Rangeworthy\' until 2003.',
		1461 => ' Previously 1461 was \'Annan\' until 2003.',
		1470 => ' Previously 1470 just \'Edinbane\' until 2003.',
		1471 => ' Previously 1471 just \'Broadford\' until 2003.',
		1477 => ' Previously 1260/1477 both \'Congleton\' until 2003.',
		1478 => ' Previously 1478 just \'Portree\' until 2003.',
		1485 => ' Previously 1485 was \'Docking\' until 2003.',
		1488 => ' Previously 1488 was \'Great Shefford\' until 2003.',
		1489 => ' Previously 1329/1489 both \'Fareham\' until 2003.',
		1491 => ' Previously 1491 was \'Nettlebed\' until 2003.',
		1543 => ' Previously 1543 was \'Burntwood\' until 2003.',
		1561 => ' Previously 1561 was \'Fordoun\' until 2003.',
		1562 => ' Previously 1384/1562 both \'Stourbridge\' until 2003.',
		1582 => ' Previously 1442/1582 both \'Markyate\' until 2003.',
		1588 => ' Previously 1588 was \'Craven Arms\' until 2003.',
		1598 => ' Previously 1598 was \'Brayford\' until 2003.',
		1661 => ' Previously 1661 was \'Wylam\' until 2003.',
		1668 => ' Previously 1668 was \'Belford\' until 2003.',
		1675 => ' Previously 1675/1676 both \'Meriden\' until 2003.',
		1680 => ' Previously 1680 just \'Craignure\' until 2003.',
		1681 => ' Previously 1681 just \'Fionnphort\' until 2003.',
		1684 => ' Previously 1684 was \'Hanley Swan\' until 2003.',
		1688 => ' Previously 1688 just \'Tobermory\' until 2003.',
		1689 => ' Previously 1322/1689/1959 all \'Swanley\' until 2003.',
		1695 => ' Previously 1695/1744 both \'Rainford\' until 2003.',
		1707 => ' Previously 1707/1727 both \'Colney Heath\' until 2003.',
		1720 => ' Previously 1720 was \'Scillonia\' until 2003.',
		1727 => ' Previously 1707/1727 both \'Colney Heath\' until 2003.',
		1737 => ' Previously 1737/1883 both \'Merstham\' until 2003.',
		1744 => ' Previously 1695/1744 both \'Rainford\' until 2003.',
		1753 => ' Previously 1753/1784/1895 all \'Iver\' until 2003.',
		1770 => ' Previously 1770 was \'Brodick\' until 2003.',
		1784 => ' Previously 1753/1784/1895 all \'Iver\' until 2003.',
		1806 => ' Previously 1806 was \'Voe\' until 2003.',
		1821 => ' Previously 1821/1828 both \'Coupar Angus\'.',
		1856 => ' Previously 1856 was \'Kirkwall\' until 2003.',
		1870 => ' Previously 1870 just \'Benbecula\' until 2003.',
		1877 => ' Previously 1877 was \'Trossachs\' until 2003.',
		1883 => ' Previously 1737/1883 both \'Merstham\' until 2003.',
		1885 => ' Previously 1885/1886 both \'Bromyard\' until 2003.',
		1889 => ' Previously 1889 was \'Dapple Heath\' until 2003.',
		1895 => ' Previously 1753/1784/1895 all \'Iver\' until 2003.',
		1908 => ' Previously 1908 was \'Wolverton\' until 2003.',
		1915 => ' Previously 1915 was \'Wearside\' until 2003.',
		1920 => ' Previously 1438/1920 both \'Knebworth\' until 2003.',
		1922 => ' Previously 1902/1922 both \'Wolverhampton\' until 2003.',
		1926 => ' Previously 1926 was \'Leamington Spa\' until 2003.',
		1928 => ' Previously 1928 was \'Frodsham\' until 2003.',
		1932 => ' Previously 1372/1932 both \'Esher\' until 2003.',
		1952 => ' Previously 1952 was \'Wellington\' until 2003.',
		1953 => ' Previously 1953 was \'Attleborough\' until 2003.',
		1959 => ' Previously 1322/1689/1959 all \'Swanley\' until 2003.',
		1963 => ' Previously 1963 was \'Templecombe\' until 2003.',
		1980 => ' Previously 1980 was \'Bulford Camp\' until 2003.',
		1983 => ' Previously 1983 was \'Ryde\' until 2003.',
		1984 => ' Previously 1984 was \'Stogumber\' until 2003.',
		1992 => ' Previously 1992 was \'Hoddesdon\' until 2003.',
		2843 => ' Previously 28 43 was \'Newcastle\' until 2003.',
		2890 => ' Previously 28 90 was \'Belfast City\' until 2003.'
	);



	/**
	 * Internal variables
	 */

	# Column titles expected in parsed CSV data
	var $titlesexpected = array(
		0 => 'Code',
		1 => 'D/DE',
		2 => 'Status',
		3 => 'Use',
		4 => 'Notes',
		5 => 'Date'
	);

	# Column titles found in parsed CSV data
	var $titlesd = array();

	# Two dimensional array of parsed CSV data
	var $datad = array();

	# Two dimensional array of temp CSV data
	var $datatemp = array();

	# Column titles for new CSV data
	var $titlesnew = array(
		0 => 'SABC',
		1 => 'D',
		2 => 'Status',
		3 => 'Use',
		4 => 'Code Length',
		5 => 'Area Type',
		6 => 'Notes',
		7 => 'Date',
		8 => 'Changes'
	);

	# Two dimensional array of new CSV data
	var $datanew = array();



	/**
	 * Constructor CSVerterSABC
	 * @param  titlesd  array  parsed column titles
	 * @param  datad    array  parsed data
	 * @return nothing
	 */
	function CSVerterSABC($titlesd = null, $datad = null)
	{
		if ( $titlesd !== null ) $this->titlesd = $titlesd;
		if ( $datad !== null ) $this->datad = $datad;

		# Check column titles are OK
		if ($this->titlesd !== $this->titlesexpected)
		{
			print "Error in column titles. Check original file for unexpected format changes.";
		}
		else
		{
			# Do this thing
			$this->fixupsabc();
		}
	}



	/**
	 * Function fixupsabc
	 * @param  none
	 * @return nothing
	 */
	function fixupsabc()
	{
		# Initialise loop
		$keynew = 0;


		# Process each record
		foreach ($this->datad as $key => $row)
		{
			# Flag entries with other than 4 digits in 'SABC' as errors
			if (strlen($this->datad[$key]["Code"]) !== 4)
			{
				$this->datanew[$keynew]["SABC"] = $this->datad[$key]["Code"];
				$this->datanew[$keynew]["D"] = $this->datad[$key]["D/DE"];
				$this->datanew[$keynew]["Status"] = $this->datad[$key]["Status"];
				$this->datanew[$keynew]["Use"] = $this->datad[$key]["Use"];
				$this->datanew[$keynew]["Code Length"] = "";
				$this->datanew[$keynew]["Area Type"] = "";
				$this->datanew[$keynew]["Notes"] = $this->datad[$key]["Notes"];
				$this->datanew[$keynew]["Date"] = $this->datad[$key]["Date"];
				$this->datanew[$keynew]["Changes"] = "SABC entry does NOT have 4 digits. What is this?";
				$keynew++;
			}
			else
			{
				# Fill in missing entries
				if (($this->datad[$key]["Code"] > 999) && ($this->datad[$key]["Code"] < 10000))
				{
					if ((($this->datad[$key]["Code"]) > (($this->datatemp[$keynew-1]["SABC"])+1)) && (($this->datatemp[$keynew-1]["SABC"] > 999) || ($keynew === 0)))
					{
						if ($keynew === 0)
						{
							$this->datatemp[$keynew-1]["SABC"] = 999;
						}
						while (($this->datad[$key]["Code"]) > (($this->datatemp[$keynew-1]["SABC"])+1))
						{
							$this->datatemp[$keynew]["SABC"] = (($this->datatemp[$keynew-1]["SABC"])+1);
							$this->datatemp[$keynew]["D"] = "";
							if ($this->datatemp[$keynew]["SABC"] < 3000)
							{
								$this->datatemp[$keynew]["Status"] = "Designated";
								$this->datatemp[$keynew]["Use"] = "Geographic - unassigned";
								$this->datatemp[$keynew]["Notes"] = "";
								$this->datatemp[$keynew]["Changes"] = " Missing SABC entry inserted. Status 'Designated' assumed. Use 'Geographic - unassigned' assumed.";
							}
							else
							{
								if (preg_match($this->protected, $this->datatemp[$keynew]["SABC"]))
								{
									$this->datatemp[$keynew]["Status"] = "Protected";
									$this->datatemp[$keynew]["Use"] = "";
									$this->datatemp[$keynew]["Notes"] = "Mobile Number Portability Codes.";
									$this->datatemp[$keynew]["Changes"] = " Missing SABC entry inserted. Status 'Protected' assumed.";
								}
								else
								{
									$this->datatemp[$keynew]["Status"] = "Not Designated";
									$this->datatemp[$keynew]["Use"] = "";
									$this->datatemp[$keynew]["Notes"] = "";
									$this->datatemp[$keynew]["Changes"] = " Missing SABC entry inserted. Status 'Not Designated' assumed.";
								}
							}
							$this->datatemp[$keynew]["Code Length"] = "";
							$this->datatemp[$keynew]["Area Type"] = "";
							$this->datatemp[$keynew]["Date"] = "";


							# Copy temp array to datanew, trim whitespace and put elements in the correct order
							foreach ($this->titlesnew as $value)
							{
								$this->datanew[$keynew][$value] = trim($this->datatemp[$keynew][$value]);
							}
							$keynew++;
						}
						$this->runrulessabc($keynew, $key, false);
						$keynew++;
					}
					else
					{
						# Dump extra entries for 3+7 areas with D digit specified
						if (((preg_match($this->sab37, $this->datad[$key]["Code"])) && (preg_match('/[0-9]/', $this->datad[$key]["D/DE"]))) !== false)
						{
							if ($this->datad[$key]["D/DE"] === "0")
							{
								$this->datad[$key]["D/DE"] = "";
								$this->runrulessabc($keynew, $key, true);
								$keynew++;
							}
							else
							{
								# DUMP ENTRIES for D === 1...9
							}
						}
						else
						{
							$this->runrulessabc($keynew, $key, false);
							$keynew++;
						}
					}
				}
				else
				{
					$this->runrulessabc($keynew, $key, false);
					$keynew++;
				}
			}
		}
	}



	/**
	 * Function runrulessabc
	 * @param  keynew  integer  new array key
	 * @param  key     integer  old array key
	 * @param  logic   boolean  entries dumped
	 * @return nothing
	 */
	function runrulessabc($keynew = null, $key = null, $logic = null)
	{
		# Combine SABC and D digits for current entry and for previous entry
		$linecodeSABCDprevious = $this->datad[$key-1]["Code"] . $this->datad[$key-1]["D/DE"];
		$linecodeSABCDcurrent = $this->datad[$key]["Code"] . $this->datad[$key]["D/DE"];


		# Dump duplicate entries
		if ($linecodeSABCDcurrent === $linecodeSABCDprevious)
		{
			$this->datanew[$keynew-1]["Changes"] = $this->datanew[$keynew-1]["Changes"] . " DUPLICATE ENTRY for '" . $linecodeSABCDprevious . "' DUMPED.";
		}
		else
		{
			# Copy 'Code' => 'SABC'
			$this->datatemp[$keynew]["SABC"] = $this->datad[$key]["Code"];


			# Copy 'D/DE' => 'D' 
			$this->datatemp[$keynew]["D"] = $this->datad[$key]["D/DE"];


			# Add note that all following D Digit repetition has been dumped
			if ($logic === true)
			{
				$this->datatemp[$keynew]["Changes"] = $this->datatemp[$keynew]["Changes"] . " 'D-Digit' repetition dumped.";
			}


			# Copy 'Status' => 'Status' fixing entries which are reserved as MNP codes
			if ((preg_match($this->protected, $this->datatemp[$keynew]["SABC"])) && ($this->datad[$key]["Status"] !== 'Protected'))
			{
				$this->datatemp[$keynew]["Status"] = "Protected";
				$this->datatemp[$keynew]["Notes"] = "Mobile Number Portability Codes.";
				$this->datatemp[$keynew]["Changes"] = " Status changed to 'Protected'. Reserved for MNP codes.";
			}
			else
			{
				$this->datatemp[$keynew]["Status"] = $this->datad[$key]["Status"];
			}


			# Copy 'Notes' => 'Notes' removing Code Length details
			$temp1 = preg_replace ($this->areacodearea, " ", $this->datad[$key]["Notes"]);
			if ($temp1 === " ") $temp1 = "";

			# ... and removing ELNS details
			$temp1 = preg_replace ($this->elnstext, " ", $temp1);
			if ($temp1 === " ") $temp1 = "";

			# Copy over if non-blank
			if ($temp1 !== "")
			{
				$this->datatemp[$keynew]["Notes"] = $temp1;
				$this->datatemp[$keynew]["Changes"] = $this->datatemp[$keynew]["Changes"] . " Moved notes to new 'Notes' column.";
			}


			# Split 'Use' => 'Use' and 'Use' => 'Notes' for "unassigned" codes with "former assignments" and fix parentheses
			if (strpos($this->datad[$key]["Use"], $this->unassigned) !== false)
			{
				preg_match($this->unassignedlong, $this->datad[$key]["Use"], $matches3);
				if ($matches3[2] !== "")
				{
					$this->datatemp[$keynew]["Use"] = $matches3[1];
					if (preg_match($this->mismatched, $matches3[2]))
					{
						$matches3[2] = $matches3[2] . ")";
						$this->datatemp[$keynew]["Changes"] = $this->datatemp[$keynew]["Changes"] . " Added missing parentheses to 'former usage' details.";
					}
					$this->datatemp[$keynew]["Notes"] = $matches3[2] . $this->datatemp[$keynew]["Notes"];
					$this->datatemp[$keynew]["Changes"] = $this->datatemp[$keynew]["Changes"] . " Split 'former usage' details to new 'Notes' column.";
				}
				else
				{
					$this->datatemp[$keynew]["Use"] = $this->datad[$key]["Use"];
				}
			}


			# Copy 'Use' => 'Use' for place names and fix incorrect spelling (SABC)
			if (!preg_match('/[0-9]/', $this->datad[$key]["D/DE"]))
			{
				if (strpos($this->datad[$key]["Use"], $this->unassigned) === false)
				{
					$linecode4 = $this->datad[$key]["Code"];
					if (ISSET($this->spelling[$linecode4]))
					{
						if ($this->spelling[$linecode4] !== $this->datad[$key]["Use"])
						{
							$this->datatemp[$keynew]["Use"] = $this->spelling[$linecode4];
							$this->datatemp[$keynew]["Changes"] = $this->datatemp[$keynew]["Changes"] . " FIXED SPELLING/NAMING: incorrect '" . $this->datad[$key]["Use"] . "' found.";
						}
						else
						{
							$this->datatemp[$keynew]["Use"] = $this->datad[$key]["Use"];
						}
					}
					else
					{
						$this->datatemp[$keynew]["Use"] = $this->datad[$key]["Use"];
					}
				}
			}


			# Copy 'Use' => 'Use' for place names and fix incorrect spelling (SABCD)
			if (preg_match('/[0-9]/', $this->datad[$key]["D/DE"]))
			{
				if (strpos($this->datad[$key]["Use"], $this->unassigned) === false)
				{
					if (ISSET($this->spelling[$linecodeSABCDcurrent]))
					{
						if ($this->spelling[$linecodeSABCDcurrent] !== $this->datad[$key]["Use"])
						{
							$this->datatemp[$keynew]["Use"] = $this->spelling[$linecodeSABCDcurrent];
							$this->datatemp[$keynew]["Changes"] = $this->datatemp[$keynew]["Changes"] . " FIXED SPELLING/NAMING: incorrect '" . $this->datad[$key]["Use"] . "' found.";
						}
						else
						{
							$this->datatemp[$keynew]["Use"] = $this->datad[$key]["Use"];
						}
					}
					else
					{
						$this->datatemp[$keynew]["Use"] = $this->datad[$key]["Use"];
					}
				}
			}


			# Copy 'Notes' => 'Code Length' for 'X Digit Area Code' entries
			if (preg_match($this->dareacode, $this->datad[$key]["Notes"], $matches4))
			{
				$this->datatemp[$keynew]["Code Length"] = $matches4[1] . ' Digit Area Code';
			}


			# Copy 'Notes' => 'Code Length' and fix wording for 'X Digit Code Area' entries
			if (preg_match($this->dcodearea, $this->datad[$key]["Notes"], $matches5))
			{
				$this->datatemp[$keynew]["Code Length"] = $matches5[1] . ' Digit Area Code';
				$this->datatemp[$keynew]["Changes"] = $this->datatemp[$keynew]["Changes"] . " CHANGED WORDING: 'Code Area' to 'Area Code'.";
			}


			# Fill in 'Code Length' for 5-Digit Mixed area codes where missing
			if ((preg_match($this->mixed5, $linecodeSABCDcurrent)))
			{
				if ((preg_match($this->areacodearea, $this->datad[$key]["Notes"])) == false)
				{
					$this->datatemp[$keynew]["Code Length"] = '5 Digit Area Code';
					$this->datatemp[$keynew]["Changes"] = $this->datatemp[$keynew]["Changes"] . " ADDED MISSING DATA: '5 Digit Area Code'.";
				}
			}


			# Fill in 'Code Length' for 4-Digit Mixed area codes where missing
			if ((preg_match($this->mixed4, $this->datad[$key]["Code"])))
			{
				if ((preg_match($this->areacodearea, $this->datad[$key]["Notes"])) == false)
				{
					if (!preg_match($this->mixed5, $linecodeSABCDcurrent))
					{
						$this->datatemp[$keynew]["Code Length"] = '4 Digit Area Code';
						$this->datatemp[$keynew]["Changes"] = $this->datatemp[$keynew]["Changes"] . " ADDED MISSING DATA: '4 Digit Area Code'.";
					} // insert 5 digit code here: if...
				}
			}


			# Change 'Code Length' for 5-Digit Mixed area codes where incorrect
			if ((preg_match($this->mixed5, $linecodeSABCDcurrent)))
			{
				preg_match($this->areacodearea, $this->datad[$key]["Notes"], $matches6);
				if ($matches6[1] !== "5")
				{
					$this->datatemp[$keynew]["Code Length"] = '5 Digit Area Code';
					$this->datatemp[$keynew]["Changes"] = $this->datatemp[$keynew]["Changes"] . " FIXED INCORRECT AREA CODE LENGTH DATA.";
				}
			}


			# Change 'Code Length' for 4-Digit Mixed area codes where incorrect
			if (preg_match($this->mixed4, $this->datad[$key]["Code"]))
			{
				if (!preg_match($this->mixed5, $linecodeSABCDcurrent))
				{
					preg_match($this->areacodearea, $this->datad[$key]["Notes"], $matches7);
					if ((ISSET($matches7[1])) && ($matches7[1] !== "4"))
					{
						$this->datatemp[$keynew]["Code Length"] = '4 Digit Area Code';
						$this->datatemp[$keynew]["Changes"] = $this->datatemp[$keynew]["Changes"] . " FIXED INCORRECT AREA CODE LENGTH DATA.";
					}
				}
			}


			# Fill in 'Code Length' for 4-Digit ELNS area codes where missing
			if ((preg_match($this->elns4, $this->datad[$key]["Code"])))
			{
				if ((preg_match($this->areacodearea, $this->datad[$key]["Notes"])) == false)
				{
					$this->datatemp[$keynew]["Code Length"] = '4 Digit Area Code';
					$this->datatemp[$keynew]["Changes"] = $this->datatemp[$keynew]["Changes"] . " ADDED MISSING DATA: '4 Digit Area Code'.";
				}
			}


			# Fill in 'Code Length' for allocated 3-Digit area codes where missing
			if ((preg_match($this->sab37, $this->datad[$key]["Code"])))
			{
				if ((preg_match($this->areacodearea, $this->datad[$key]["Notes"])) == false)
				{
					if ((preg_match($this->unassignedlong, $this->datad[$key]["Use"])) == false)
					{
						$this->datatemp[$keynew]["Code Length"] = '3 Digit Area Code';
						$this->datatemp[$keynew]["Changes"] = $this->datatemp[$keynew]["Changes"] . " ADDED MISSING DATA: '3 Digit Area Code'.";
					}
				}
			}


			# Fill in 'Code Length' for allocated 2-Digit area codes where missing
			if ((preg_match($this->sa28, $this->datad[$key]["Code"])))
			{
				if ((preg_match($this->areacodearea, $this->datad[$key]["Notes"])) == false)
				{
					if (!preg_match($this->expansion, $this->datad[$key]["Use"]))
					{
						$this->datatemp[$keynew]["Code Length"] = '2 Digit Area Code';
						$this->datatemp[$keynew]["Changes"] = $this->datatemp[$keynew]["Changes"] . " ADDED MISSING DATA: '2 Digit Area Code'.";
					}
				}
			}


			# Fill in 3-Digit area code Director data where missing
			if ((preg_match($this->director3, $this->datad[$key]["Code"]) == true) && (preg_match($this->directortext, $this->datad[$key]["Notes"]) !== true))
			{
				$this->datatemp[$keynew]["Area Type"] = "Director";
				$this->datatemp[$keynew]["Changes"] = $this->datatemp[$keynew]["Changes"] . " Added missing 'Director' data.";
			}


			# Fill in 2-Digit area code Director data where missing
			if ((preg_match($this->director2, $this->datad[$key]["Code"]) == true) && (preg_match($this->directortext, $this->datad[$key]["Notes"]) !== true))
			{
				if (!preg_match($this->expansion, $this->datad[$key]["Use"]))
				{
					$this->datatemp[$keynew]["Area Type"] = "Director";
					$this->datatemp[$keynew]["Changes"] = $this->datatemp[$keynew]["Changes"] . " Added missing 'Director' data.";
				}
			}


			# Fill in Mixed data for 4 and 5-Digit area codes where missing
			if ((preg_match($this->mixed4, $this->datad[$key]["Code"]) == true) && (preg_match($this->mixedtext, $this->datad[$key]["Notes"]) !== true))
			{
				$this->datatemp[$keynew]["Area Type"] = "Mixed";
				$this->datatemp[$keynew]["Changes"] = $this->datatemp[$keynew]["Changes"] . " Added missing 'Mixed' data.";
			}


			# Fill in missing area code length data for all allocated 4 digit area codes
			if (preg_match('/(^1)/', $this->datad[$key]["Code"]))
			{
				if ((preg_match($this->mixed4, $this->datad[$key]["Code"]) == false) && (preg_match($this->elns4, $this->datad[$key]["Code"]) == false) && (preg_match($this->sab37, $this->datad[$key]["Code"]) == false) && (preg_match($this->sa28, $this->datad[$key]["Code"]) == false) && (preg_match($this->unassignedlong, $this->datad[$key]["Use"]) == false) && (preg_match($this->expansion, $this->datad[$key]["Use"]) == false))
					{
						$this->datatemp[$keynew]["Code Length"] .= "4 Digit Area Code";
						$this->datatemp[$keynew]["Changes"] = $this->datatemp[$keynew]["Changes"] . " Added missing data: '4 Digit Area Code'.";
					}
			}


			# Copy 'Notes' => 'Area Type' for ELNS areas...
			if (preg_match($this->elnstext, $this->datad[$key]["Notes"]))
			{
				$this->datatemp[$keynew]["Area Type"] = 'ELNS';
				$this->datatemp[$keynew]["Changes"] = $this->datatemp[$keynew]["Changes"] . " Moved 'ELNS' data to separate column.";

				# ...and for previously unknown ELNS areas
				if ((!(preg_match($this->elns4, $this->datad[$key]["Code"]))) && (!(preg_match($this->elns3, $this->datad[$key]["Code"]))) && (!(preg_match($this->elns2, $this->datad[$key]["Code"]))))
				{
					$this->datatemp[$keynew]["Changes"] = $this->datatemp[$keynew]["Changes"] . " Check listings; this SABC value is not previously noted as being an ELNS area.";
				}
			}


			# Fill in ELNS data in 'Area Type' column where missing, for 4-Digit area codes
			if ((preg_match($this->elns4, $this->datad[$key]["Code"]) == true) && (!(preg_match($this->elnstext, $this->datad[$key]["Notes"]))))
			{
				$this->datatemp[$keynew]["Area Type"] = "ELNS";
				$this->datatemp[$keynew]["Changes"] = $this->datatemp[$keynew]["Changes"] . " ADDED MISSING 'ELNS' DATA.";
			}


			# Fill in ELNS data in 'Area Type' column where missing, for 3-Digit area codes
			if ((preg_match($this->elns3, $this->datad[$key]["Code"]) == true) && (!(preg_match($this->elnstext, $this->datad[$key]["Notes"]))))
			{
				$this->datatemp[$keynew]["Area Type"] = "ELNS";
				$this->datatemp[$keynew]["Changes"] = $this->datatemp[$keynew]["Changes"] . " ADDED MISSING 'ELNS' DATA.";
			}


			# Fill in ELNS data in 'Area Type' column where missing, for 2-Digit area codes
			if ((preg_match($this->elns2, $this->datad[$key]["Code"]) == true) && (!(preg_match($this->elnstext, $this->datad[$key]["Notes"]))))
			{
				if (!preg_match($this->expansion, $this->datad[$key]["Use"]))
				{
					$this->datatemp[$keynew]["Area Type"] = "ELNS";
					$this->datatemp[$keynew]["Changes"] = $this->datatemp[$keynew]["Changes"] . " ADDED MISSING 'ELNS' DATA.";
				}
			}


			# Fill in new 'Notes' column with new notes and mention in 'Changes' column
			if (ISSET($this->addnotes[$linecodeSABCDcurrent]))
			{
				$this->datatemp[$keynew]["Notes"] = $this->datatemp[$keynew]["Notes"] . $this->addnotes[$linecodeSABCDcurrent];
				$this->datatemp[$keynew]["Changes"] = $this->datatemp[$keynew]["Changes"] . " Added new notes.";
			}


			# Fill in new 'Notes' column with old area code names from before 2003
			if (ISSET($this->oldallocs[$linecodeSABCDcurrent]))
			{
				$this->datatemp[$keynew]["Notes"] = $this->datatemp[$keynew]["Notes"] . $this->oldallocs[$linecodeSABCDcurrent];
				$this->datatemp[$keynew]["Changes"] = $this->datatemp[$keynew]["Changes"] . " Added old naming details.";
			}


			# Copy 'Date' => 'Date'
			 $this->datatemp[$keynew]["Date"] = $this->datad[$key]["Date"];


			# Trim whitespace in 'Use' column and add 'Notes' if done
			if (!($this->datatemp[$keynew]["Use"] === trim($this->datatemp[$keynew]["Use"])))
			{
				$this->datatemp[$keynew]["Use"] = trim($this->datatemp[$keynew]["Use"]);
				$this->datatemp[$keynew]["Changes"] = $this->datatemp[$keynew]["Changes"] . " WHITESPACE TRIMMED IN 'Use' COLUMN.";
			}


			# Fill in blanks in the temporary array
			foreach ($this->titlesnew as $value)
			{
				if ($this->datatemp[$keynew][$value] == null)
				{
					$this->datatemp[$keynew][$value] = "";
				}
			}


			# Copy temp array to datanew, trim whitespace and put elements in the correct order
			foreach ($this->titlesnew as $value)
			{
				$this->datanew[$keynew][$value] = trim($this->datatemp[$keynew][$value]);
			}
		}
	}
}
?>